Skip to content

Conversation

@WSQS
Copy link
Owner

@WSQS WSQS commented Nov 9, 2025

Summary by CodeRabbit

Release Notes

  • Refactor

    • Application architecture refactored with improved structural organization and design patterns for enhanced maintainability
  • Chores

    • Updated and standardized CI/CD workflows across platforms for consistency
    • Refined build system configuration
    • Introduced cleaner module structure with better separation of concerns

@coderabbitai
Copy link

coderabbitai bot commented Nov 9, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'review'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

This PR refactors the SDL application from a procedural callback-driven architecture to an object-oriented design. A new sopho::App base class is introduced with virtual lifecycle methods (init, iterate, event, quit). The application implements this interface via a UserApp class. Supporting SDL callback infrastructure is added in a new implementation file. GitHub Actions workflows are reformatted for consistency.

Changes

Cohort / File(s) Change Summary
GitHub Actions workflow formatting
.github/workflows/cmake-linux.yml, .github/workflows/cmake-windows.yml
Restructured step indentation and spacing; converted inline multiline commands into explicit step blocks for Configure, Build, Test, Install, and Upload operations. No functional behavior changes.
Application OO refactoring
main.cpp
Replaced procedural SDL callback code with a UserApp class derived from sopho::App; instance members replace global state; added virtual method overrides for lifecycle management and factory function create_app().
SDL wrapper module interface
sdl_wrapper/sdl_wrapper.app.ixx
New C++ module interface defining the abstract sopho::App class with pure virtual methods for init, iterate, event, and quit.
SDL wrapper callback implementation
sdl_wrapper/sdl_callback_implement.cpp
New implementation file providing SDL3 callback functions (SDL_AppInit, SDL_AppIterate, SDL_AppEvent, SDL_AppQuit) that delegate to the sopho::App interface methods.
SDL wrapper module exports
sdl_wrapper/sdl_wrapper.ixx
Added export import :app; to re-export the new app module partition.
SDL wrapper module configuration
sdl_wrapper/CMakeLists.txt
Added sdl_wrapper.app.ixx to the module file set and introduced sdl_callback_implement.cpp as a private source.
SDL wrapper buffer module reordering
sdl_wrapper/sdl_wrapper.buffer.ixx
Relocated module export directive from beginning to after include directive; no semantic changes.

Sequence Diagram(s)

sequenceDiagram
    participant SDL as SDL3 Runtime
    participant Callback as sdl_callback_implement.cpp
    participant App as sopho::App (UserApp)

    SDL->>Callback: SDL_AppInit(void **appstate, argc, argv)
    Callback->>App: create_app()
    App-->>Callback: UserApp*
    Callback->>App: app->init(argc, argv)
    App-->>Callback: SDL_AppResult
    Callback-->>SDL: result

    loop Per Frame
        SDL->>Callback: SDL_AppIterate(void *appstate)
        Callback->>App: app->iterate()
        App-->>Callback: SDL_AppResult
        Callback-->>SDL: result
    end

    SDL->>Callback: SDL_AppEvent(void *appstate, SDL_Event *event)
    Callback->>App: app->event(event)
    App-->>Callback: SDL_AppResult
    Callback-->>SDL: result

    SDL->>Callback: SDL_AppQuit(void *appstate, SDL_AppResult result)
    Callback->>App: app->quit(result)
    App-->>Callback: (void)
    Callback-->>SDL: done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Extra attention areas:
    • main.cpp: Verify the UserApp class correctly initializes/cleans up all SDL resources (window, device, buffers, pipeline); ensure virtual method overrides properly encapsulate former global state.
    • sdl_wrapper/sdl_callback_implement.cpp: Review the delegation pattern and static_cast usage; confirm error handling propagates correctly through the callback chain.
    • sdl_wrapper/CMakeLists.txt: Validate that the module interface file and private implementation are correctly linked and discoverable by the build system.
    • Module import/export chain (sdl_wrapper.ixx, sdl_wrapper.app.ixx, sdl_wrapper.buffer.ixx): Ensure module partitions are properly ordered and exported for downstream consumers.

Possibly related PRs

  • Cpp20module #1: Modifies sdl_wrapper module structure and CMake target configuration with similar module interface and target_sources changes.

Poem

A class doth rise from callbacks old,
Where UserApp breaks the mold,
Virtual methods dance and sway,
Object-oriented comes to play! 🐰✨
From globals tamed to members neat,
The architecture's now complete!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Add Class app as a Context' is vague and does not clearly convey the main purpose of the changes, which involve refactoring SDL application code to use an object-oriented App class pattern with virtual methods and workflow restructuring. Improve the title to be more specific about the primary change, such as 'Refactor SDL app lifecycle to object-oriented App class pattern' or 'Introduce abstract App class for application lifecycle management'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch class_app

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@WSQS
Copy link
Owner Author

WSQS commented Nov 9, 2025

@coderabbitai configuration

@coderabbitai
Copy link

coderabbitai bot commented Nov 9, 2025

CodeRabbit configuration
language: en-US
tone_instructions: ''
early_access: false
enable_free_tier: true
reviews:
  profile: chill
  request_changes_workflow: false
  high_level_summary: true
  high_level_summary_placeholder: '@coderabbitai summary'
  high_level_summary_in_walkthrough: false
  auto_title_placeholder: '@coderabbitai'
  auto_title_instructions: ''
  review_status: true
  commit_status: true
  fail_commit_status: false
  collapse_walkthrough: false
  changed_files_summary: true
  sequence_diagrams: true
  estimate_code_review_effort: true
  assess_linked_issues: true
  related_issues: true
  related_prs: true
  suggested_labels: true
  labeling_instructions: []
  auto_apply_labels: false
  suggested_reviewers: true
  auto_assign_reviewers: false
  in_progress_fortune: true
  poem: true
  path_filters: []
  path_instructions: []
  abort_on_close: true
  disable_cache: false
  auto_review:
    enabled: true
    auto_incremental_review: true
    ignore_title_keywords: []
    labels: []
    drafts: false
    base_branches: []
    ignore_usernames: []
  finishing_touches:
    docstrings:
      enabled: true
    unit_tests:
      enabled: true
  pre_merge_checks:
    docstrings:
      mode: warning
      threshold: 80
    title:
      mode: warning
      requirements: ''
    description:
      mode: warning
    issue_assessment:
      mode: warning
    custom_checks: []
  tools:
    ast-grep:
      rule_dirs: []
      util_dirs: []
      essential_rules: true
      packages: []
    shellcheck:
      enabled: true
    ruff:
      enabled: true
    markdownlint:
      enabled: true
    github-checks:
      enabled: true
      timeout_ms: 90000
    languagetool:
      enabled: true
      enabled_rules: []
      disabled_rules: []
      enabled_categories: []
      disabled_categories: []
      enabled_only: false
      level: default
    biome:
      enabled: true
    hadolint:
      enabled: true
    swiftlint:
      enabled: true
    phpstan:
      enabled: true
      level: default
    phpmd:
      enabled: true
    phpcs:
      enabled: true
    golangci-lint:
      enabled: true
    yamllint:
      enabled: true
    gitleaks:
      enabled: true
    checkov:
      enabled: true
    detekt:
      enabled: true
    eslint:
      enabled: true
    flake8:
      enabled: true
    rubocop:
      enabled: true
    buf:
      enabled: true
    regal:
      enabled: true
    actionlint:
      enabled: true
    pmd:
      enabled: true
    clang:
      enabled: true
    cppcheck:
      enabled: true
    semgrep:
      enabled: true
    circleci:
      enabled: true
    clippy:
      enabled: true
    sqlfluff:
      enabled: true
    prismaLint:
      enabled: true
    pylint:
      enabled: true
    oxc:
      enabled: true
    shopifyThemeCheck:
      enabled: true
    luacheck:
      enabled: true
    brakeman:
      enabled: true
    dotenvLint:
      enabled: true
    htmlhint:
      enabled: true
    checkmake:
      enabled: true
    osvScanner:
      enabled: true
chat:
  art: true
  auto_reply: true
  integrations:
    jira:
      usage: auto
    linear:
      usage: auto
knowledge_base:
  opt_out: false
  web_search:
    enabled: true
  code_guidelines:
    enabled: true
    filePatterns: []
  learnings:
    scope: auto
  issues:
    scope: auto
  jira:
    usage: auto
    project_keys: []
  linear:
    usage: auto
    team_keys: []
  pull_requests:
    scope: auto
  mcp:
    usage: auto
    disabled_servers: []
code_generation:
  docstrings:
    language: en-US
    path_instructions: []
  unit_tests:
    path_instructions: []
review:
  style: concise
  severity_threshold: medium
  enable_tests: true

@WSQS
Copy link
Owner Author

WSQS commented Nov 9, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Nov 9, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (4)
main.cpp (2)

61-248: Consider extracting helper methods for improved readability.

The init method is quite long (~187 lines) and handles multiple responsibilities: window/device creation, shader compilation, pipeline setup, buffer creation, and ImGui initialization. Consider extracting logical sections into private helper methods (e.g., initShaders(), initPipeline(), initBuffers(), initImGui()).


265-292: Extract duplicate buffer upload logic.

The buffer upload code (lines 265-292) duplicates the logic from the init method (lines 189-215). Consider extracting this into a private helper method like uploadVertexData() to follow the DRY principle.

Example refactoring:

private:
    void uploadVertexData() {
        Vertex *data = (Vertex *)SDL_MapGPUTransferBuffer(device, transferBuffer, false);
        SDL_memcpy(data, (void *)vertices, sizeof(vertices));
        SDL_UnmapGPUTransferBuffer(device, transferBuffer);
        
        SDL_GPUCommandBuffer *commandBuffer = SDL_AcquireGPUCommandBuffer(device);
        SDL_GPUCopyPass *copyPass = SDL_BeginGPUCopyPass(commandBuffer);
        
        SDL_GPUTransferBufferLocation location{};
        location.transfer_buffer = transferBuffer;
        location.offset = 0;
        
        SDL_GPUBufferRegion region{};
        region.buffer = vertexBuffer;
        region.size = sizeof(vertices);
        region.offset = 0;
        
        SDL_UploadToGPUBuffer(copyPass, &location, &region, true);
        SDL_EndGPUCopyPass(copyPass);
        SDL_SubmitGPUCommandBuffer(commandBuffer);
    }
sdl_wrapper/sdl_callback_implement.cpp (2)

18-21: Add defensive null check.

While appstate should not be null in normal operation, adding a null check provides defense-in-depth against potential SDL framework issues or future changes.

Apply this diff:

 SDL_AppResult SDL_AppIterate(void *appstate) {
     auto *app = static_cast<sopho::App *>(appstate);
+    if (!app) return SDL_APP_FAILURE;
     return app->iterate();
 }

23-26: Add defensive null check.

While appstate should not be null in normal operation, adding a null check provides defense-in-depth against potential SDL framework issues or future changes.

Apply this diff:

 SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
     auto *app = static_cast<sopho::App *>(appstate);
+    if (!app) return SDL_APP_FAILURE;
     return app->event(event);
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f49279 and 67657c2.

📒 Files selected for processing (8)
  • .github/workflows/cmake-linux.yml (1 hunks)
  • .github/workflows/cmake-windows.yml (2 hunks)
  • main.cpp (2 hunks)
  • sdl_wrapper/CMakeLists.txt (1 hunks)
  • sdl_wrapper/sdl_callback_implement.cpp (1 hunks)
  • sdl_wrapper/sdl_wrapper.app.ixx (1 hunks)
  • sdl_wrapper/sdl_wrapper.buffer.ixx (1 hunks)
  • sdl_wrapper/sdl_wrapper.ixx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: build (Release, gcc)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (Release, clang)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (windows-latest, Release, clang)
🔇 Additional comments (5)
sdl_wrapper/sdl_wrapper.buffer.ixx (1)

4-6: LGTM! Correct module pattern.

The reordering to use the global module fragment (module;) before the include directive follows the correct C++20 module pattern, allowing SDL headers to be included before the module partition export.

sdl_wrapper/sdl_wrapper.ixx (1)

6-7: LGTM! Proper module partition exports.

The addition of export import :app; correctly re-exports the new app partition alongside the existing buffer partition.

sdl_wrapper/CMakeLists.txt (1)

12-14: LGTM! Build configuration updated correctly.

The addition of sdl_wrapper.app.ixx to the public module set and sdl_callback_implement.cpp as a private implementation file is correct.

sdl_wrapper/sdl_wrapper.app.ixx (1)

8-19: LGTM! Well-designed interface.

The App interface is clean and well-structured:

  • Virtual destructor ensures proper cleanup of derived classes
  • Pure virtual methods enforce a clear lifecycle contract (init → iterate → event → quit)
  • Method signatures align with SDL3 callback conventions
main.cpp (1)

359-375: LGTM! Proper resource cleanup.

The cleanup order is correct: ImGui context is destroyed first, followed by GPU resources (buffers, pipeline), then the device, and finally the window. All resources allocated in init are properly released.

vertices[0].z = node[2];
class UserApp : public sopho::App {

sopho::BufferWrapper BufferWrapper{};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Unused member variable.

The BufferWrapper member is declared but never used in the implementation. Consider removing it or implementing its intended functionality.

🤖 Prompt for AI Agents
In main.cpp around line 53, the sopho::BufferWrapper BufferWrapper{} member is
declared but never used; either remove this unused member declaration or
implement its intended usage. If it's not needed, delete the declaration and
recompile/run tests; if it should be used, initialize it properly where
required, replace direct buffer accesses with member calls, and update
constructors/cleanup to manage its lifetime so the compiler no longer reports it
as unused.

Comment on lines +378 to 380
sopho::App *create_app() {
return new UserApp();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Memory leak: App instance is never deleted.

The factory function allocates a UserApp instance with new, but there's no corresponding delete in the codebase. The SDL_AppQuit callback in sdl_callback_implement.cpp (line 28-31) calls app->quit() but doesn't delete the app pointer.

Apply this fix to sdl_wrapper/sdl_callback_implement.cpp:

 void SDL_AppQuit(void *appstate, SDL_AppResult result) {
     auto *app = static_cast<sopho::App *>(appstate);
     app->quit(result);
+    delete app;
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In sdl_wrapper/sdl_callback_implement.cpp around lines 28 to 31, the SDL_AppQuit
callback only calls app->quit() but never deletes the App instance returned by
create_app(), causing a memory leak; modify the callback to check that app is
non-null, call app->quit(), then delete app and set the pointer to nullptr (or
otherwise transfer ownership to a smart pointer) so the allocated UserApp is
freed; ensure this deletion is thread-safe with respect to SDL callbacks and
avoid double-deletion by clearing any global or static references to app after
deletion.

Comment on lines +12 to +16
SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
auto app = create_app();
*appstate = app;
return app->init(argc, argv);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing error handling for failed allocation.

If create_app() fails and returns nullptr (e.g., out of memory), the code will dereference a null pointer when calling app->init(). Add a null check and return an appropriate error code.

Apply this diff:

 SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
     auto app = create_app();
+    if (!app) {
+        return SDL_APP_FAILURE;
+    }
     *appstate = app;
     return app->init(argc, argv);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
auto app = create_app();
*appstate = app;
return app->init(argc, argv);
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {
auto app = create_app();
if (!app) {
return SDL_APP_FAILURE;
}
*appstate = app;
return app->init(argc, argv);
}
🤖 Prompt for AI Agents
In sdl_wrapper/sdl_callback_implement.cpp around lines 12 to 16, handle the case
where create_app() returns nullptr: after calling create_app(), check if app is
nullptr, set *appstate = nullptr (or leave unchanged if preferred), and return
an appropriate failure SDL_AppResult (e.g., an out-of-memory or generic error
enum value used by this project) instead of calling app->init(); this prevents
dereferencing a null pointer and surfaces a clear error path.

Comment on lines +28 to +31
void SDL_AppQuit(void *appstate, SDL_AppResult result) {
auto *app = static_cast<sopho::App *>(appstate);
app->quit(result);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing cleanup and null check.

Two issues:

  1. The app instance is never deleted, causing a memory leak (already noted in main.cpp review)
  2. No null check on appstate

Apply this diff:

 void SDL_AppQuit(void *appstate, SDL_AppResult result) {
     auto *app = static_cast<sopho::App *>(appstate);
+    if (!app) return;
     app->quit(result);
+    delete app;
 }
🤖 Prompt for AI Agents
In sdl_wrapper/sdl_callback_implement.cpp around lines 28-31, add a null check
for appstate and ensure the App instance is deleted to avoid leaking memory:
first return immediately if appstate is nullptr, then static_cast to
sopho::App*, call app->quit(result) as before, and finally delete the app
pointer (and optionally set it to nullptr in the caller if ownership is shared)
so the instance is freed after quit.

@WSQS WSQS merged commit 45dd084 into dynamic_vertice Nov 9, 2025
21 checks passed
@WSQS WSQS deleted the class_app branch November 9, 2025 11:46
@coderabbitai coderabbitai bot mentioned this pull request Nov 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants